﻿using System;
using System.Collections.Generic;
using System.Web;
using System.DirectoryServices;

/**
    * ADUser class for performing operations and value retrievals on Active Directory Objects
    * 
    * @version 1.0
    * @authors: 
    *      Fabien DUCHENE f.duchene@car-online.fr 
    *      Ludovic FANTON www.fanton.l@gmail.com 
    */
namespace ChgPwd
{
    public class ADUser
    {
        //Ldap port used by the method Invoke
        private String strPort = "389";

        //Invoke parameters for SetOption
        private const long  ADS_OPTION_PASSWORD_PORTNUMBER  = 6;
        private const long  ADS_OPTION_PASSWORD_METHOD      = 7;
        private const int   ADS_PASSWORD_ENCODE_REQUIRE_SSL = 0;
        private const int   ADS_PASSWORD_ENCODE_CLEAR       = 1;
		public static const string LDAPConnectionString = "servername/OU=BLABLA,DC=ADDS_domain,DC=DC=com";

        //used to retrieve the user's current password, for security checks
        private SearchResult        result;
        private DirectorySearcher   MySearch;
        private PropertyCollection  userProperties;

        private string LDAPLogin;
        private string LDAPPassword;

        protected string samAccountName;

        /**
         * ADUser constructor
         * Used to retrieve the user's old password and sets the new one 
         * @param FullUserName      user's logon name
         * @param OldPassword.Text  user's current password
         * @return  bool            true if worked, false if password's complexity politics didn't match
         */
        public ADUser(String FullUserName, string CurrentPassword)
        {
            LDAPLogin = FullUserName;
            LDAPPassword = CurrentPassword;
            //Drop the "corp\" and retrieve the "surname.name"
            samAccountName = FullUserName.Split('\\') [1];
           
            //try to search the AD user LDAP object with the accountname samAccountName
            SearchUser(samAccountName);
        }

        private DirectoryEntry getaDirConnection() {
            //Secure connection to the LDAP
            return new DirectoryEntry(
                ("LDAP://"+ADUser.LDAPConnectionString),
                LDAPLogin,
                LDAPPassword,
                AuthenticationTypes.Signing |
                AuthenticationTypes.Sealing |
                AuthenticationTypes.Secure
            );
        }

        /* *
        * Searching for a user with his samaccountname
        *  @param the samaccountname
        *  @return the ldap directoryentry for which the user did match
        */
        private DirectoryEntry SearchUser(string samAccountName)
        {
            DirectoryEntry DirConnection = getaDirConnection();
            MySearch = new DirectorySearcher(DirConnection);
            MySearch.SearchRoot = DirConnection;
            MySearch.Filter = "(&(objectClass=user)(sAMAccountName=" + samAccountName + "))";
            MySearch.SearchScope = SearchScope.Subtree;

            if (MySearch.FindAll().Count == 0)
                throw new Exception("no result found");

            SearchResult Result = MySearch.FindOne();
            DirectoryEntry UserEntry = Result.GetDirectoryEntry();

            return UserEntry;
            
        }

        /* *
         * Getting user's current password
         *  @param none
         *  @return securely stored user's current password
         */
        private String getPassword()
        {
            DirectoryEntry UserEntry = SearchUser(samAccountName);
            byte[] bytearr = (byte[]) UserEntry.Properties["userPassword"].Value; 
            char[] result = new char[bytearr.Length];
            bytearr.ToString().CopyTo(0,result,0,bytearr.ToString().Length);
            return new String(result);
        }

        /**
         * Change user's password
         * @param DesirednewPassword    the new password from the form
         * @return bool                 true if worked, false if password's complexity politics didn't match
         */
        public bool ChangePassword(String DesirednewPassword)
        {
           
            DirectoryEntry MyUserEntry = SearchUser(samAccountName);

            //Security options
            MyUserEntry.Invoke("SetOption", new object[] { ADS_OPTION_PASSWORD_PORTNUMBER, Int32.Parse(strPort) });
            MyUserEntry.Invoke("SetOption", new object[] { ADS_OPTION_PASSWORD_METHOD, ADS_PASSWORD_ENCODE_CLEAR });

            /*
             * Effective password change
             */
            try
            {
                MyUserEntry.Invoke("SetPassword", new object[] { DesirednewPassword });
            }
            catch (Exception e)
            {
                throw new Exception(Language.COULD_NOT_CHANGE_PASSWORD+"\n"+Language.PWD_COMPLEXITY_POLICY_CONTENT);
            }
            //saving changes
            
            MyUserEntry.CommitChanges();

           
            return true;
        }

    }

}